/*
 * This file is part of JFlowMap.
 *
 * Copyright 2009 Ilya Boyandin
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package fons.navigator.util.piccolo;

import java.awt.Font;
import java.awt.Paint;
import java.awt.geom.RoundRectangle2D;

import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.nodes.PPath;
import edu.umd.cs.piccolo.util.PBounds;
import edu.umd.cs.piccolo.util.PPaintContext;

/**
 * @author Ilya Boyandin
 */
public class Legend extends PPath {

	private static final long serialVersionUID = -8907313603307434727L;

	static final Font LABEL_FONT = new Font("Arial", Font.BOLD, 16);
	static final double MAX_HEIGHT = 600;

	private final double gapBetweenLines = 4;
	private final double gapAfterHeader = 4;
	private final double paddingX = 8, paddingY = 4;
	private final double startY = 8;
	private final double startX = 8;
	private boolean hidden = false;

	private ItemProducer itemsProducer;

	private PButton hideButton;
	private PBasicInputEventHandler inputEventHandler;

	public Legend(Paint paint, ItemProducer itemsProducer) {
		super(new RoundRectangle2D.Double(4,4,140,250,10,20));

		this.itemsProducer = itemsProducer;
		setPaint(paint);
		setStroke(null);
		setStrokePaint(null);
		setPickable(false);
		this.setOffset(0, 55);
		update();
	}

	public ItemProducer getItemsProducer() {
		return itemsProducer;
	}

	public void setItemsProducer(ItemProducer itemsProducer) {
		this.itemsProducer = itemsProducer;
	}

	public interface ItemProducer {
		PNode createHeader();

		Iterable<PNode> createItems();
	}


	public void update() {
		removeAllChildren();

		PNode header = itemsProducer.createHeader();

		double posX = startX + paddingX;
		double posY = startY + paddingY;

		double headerWidth, headerHeight;
		if (header != null) {
			addChild(header);
			PNodes.setPosition(header, posX, posY, true);
			PBounds headerBounds = header.getFullBoundsReference();
			headerWidth = headerBounds.getWidth();
			headerHeight = headerBounds.getHeight();
			posY += headerHeight + paddingY + gapAfterHeader;
		} else {
			headerWidth = headerHeight = 0;
		}


		double maxItemWidth = Double.NaN;
		double height = headerHeight + paddingY + gapAfterHeader + startY;
		Iterable<PNode> itemNodes = itemsProducer.createItems();
		
		for (PNode item: itemNodes) {
			if (posY >= MAX_HEIGHT) {
				posY = startY + paddingY + headerHeight + paddingY + gapAfterHeader;
				posX += maxItemWidth + paddingX;
				maxItemWidth = Double.NaN;
			}
			
			addChild(item);
			PNodes.setPosition(item, posX, posY, true);

			PBounds itemBounds = item.getFullBoundsReference();
			final double itemWidth = itemBounds.getWidth();
			if (Double.isNaN(maxItemWidth)  ||  maxItemWidth < itemWidth) {
				maxItemWidth = itemWidth;
			}
			
			posY += itemBounds.getHeight() + gapBetweenLines;
			height += itemBounds.getHeight() + gapBetweenLines;
		}

		setWidth(Math.max(headerWidth, posX + maxItemWidth) + paddingX * 2);
		setHeight(height + gapBetweenLines + paddingY*2);

		if (this.hideButton != null) {
			this.removeChild(hideButton);
		}

		
		hideButton = new PButton(hidden ? ">" : "<", false, new Font("Arial", Font.BOLD, 16));
		hideButton.setX(this.getWidth() + 10);
		hideButton.setY(hideButton.getHeight() - 5);
		addChild(hideButton);

		this.inputEventHandler = new PBasicInputEventHandler() {
			private double oldPosX = startX;

			@Override
			public void mouseClicked(PInputEvent event) {
				if (hidden) {
					Legend.this.animateToPositionScaleRotation(oldPosX,
							Legend.this.getOffset().getY(), 1.0, 0.0, 1000);
					hidden = false;
					hideButton.setText("<");
				} else {
					Legend.this.animateToPositionScaleRotation(0.5*(-Legend.this.getWidth()),
							Legend.this.getOffset().getY(), 0.5, 0.0, 1000);
					hidden = true;
					hideButton.setText(">");
				}

			}
		};
		hideButton.addInputEventListener(this.inputEventHandler);

		this.moveToFront();
	}


	@Override
	public void paint(PPaintContext pc) {
		final int oldQuality = pc.getRenderQuality();
		if (oldQuality != PPaintContext.HIGH_QUALITY_RENDERING) {
			pc.setRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING);
		}

		super.paint(pc);

		if (oldQuality != PPaintContext.HIGH_QUALITY_RENDERING) {
			pc.setRenderQuality(oldQuality);
		}
	}


}
